<!-- components/InterviewQuestionGenerator.vue -->
<template>
  <div class="question-generator">
  </div>
</template>

<script>
import CryptoJS from 'crypto-js';
import { mapGetters } from 'vuex';

export default {
  name: 'InterviewQuestionGenerator',
  props: {
    modelDomain: {
      type: String,
      default: 'generalv3.5'
    },
    appId: {
      type: String,
      default: 'e9f15e7b'
    },
    apiKey: {
      type: String,
      default: '8f4950aa42fdca8eac189b3edb74da82'
    },
    apiSecret: {
      type: String,
      default: 'YTk4MzhhOGY5MDNjNWI2ZjAzYjEwMWVi'
    },
    modelHttpUrl: {
      type: [String,URL],
      default: 'https://spark-api.xf-yun.com/v3.5/chat'
    }
  },
  data() {
    return {
      modelWS: null,
      isLoading: false,
      responseBuffer: '',
      currentScenario: 'default', // 当前场景
      // 场景配置：不同场景的生成要求和提示词模板
      scenarioConfig: {
        default: {
          name: '默认面试场景',
          promptTemplate: `你是一名专业的面试官，现在请根据以下候选人信息和上下文，生成一个自然、专业、贴合岗位的下一个面试问题。

         【候选人信息】
        - 目标岗位：{position}
        - 技术领域：{techField}
        - 擅长语言：{languages}
        - 基础信息：{basicInfo}
        - 教育背景：{educationInfo}
        - 实习经历：{internshipInfo}
        - 项目经历：{projectInfo}
        - 校园/社会经历：{socialInfo}
        - 技能特长：{skillsInfo}
        - 证书/奖项：{certInfo}
        - 个人简介：{selfDesc}

        【面试上下文】
        - 当前问题：{currentQuestion}
        - 候选人回答：{userAnswer}

        【生成要求】
        1. 新问题应与当前问题和候选人回答相关，结合岗位、领域、语言和简历信息，深入考察候选人能力。
        2. 问题应具有专业性和针对性，避免无关或重复。
        3. 保持问题的开放性和自然流畅，模拟真实面试官的提问风格。
        4. 可以结合候选人简历中的亮点或疑点进行追问。
        5. 只输出下一个面试问题，不要有任何额外说明。

        请直接输出生成的问题。`
        },
        technical: {
          name: '技术面试',
          promptTemplate: `
        你是一名专业的技术面试官，请根据以下候选人信息和问题上下文，生成一个专业、深入、贴合岗位技术要求的下一个技术面试问题。注意要结合候选者的回答，注意问题不要太长！！！1或者2个问题就行。

        【候选人信息】
        - 目标岗位：{position}
        - 技术领域：{techField}
        - 擅长语言：{languages}
        - 基础信息：{basicInfo}
        - 实习经历：{internshipInfo}
        - 项目经历：{projectInfo}
        - 个人简介：{selfDesc}

        【面试上下文】
        - 当前问题：{currentQuestion}
        - 候选人回答：{userAnswer}

        【生成要求】
        1. 新问题应紧密结合岗位、技术领域、项目经历、技能特长等技术相关信息，深入考察候选人的技术能力和实际经验。
        2. 可以针对候选人简历中的技术亮点、项目细节、技术难点或技术栈进行追问。
        3. 问题应具有技术深度和针对性，避免泛泛而谈。
        4. 保持问题的开放性和专业性，模拟真实技术面试官的提问风格。
        5. 只输出下一个技术面试问题，不要有任何额外说明。

        请直接输出生成的问题。注意问题不要太长！！！1或者2个问题就行`
        },
        pressure: {
          name: '压力面试',
          promptTemplate: `
        你是一名压力面试官，请根据以下候选人信息和上下文，对候选人的回答进行点评。注意要结合候选者的回答，注意问题不要太长！！！1个问题就行。

        【候选人信息】
        - 目标岗位：{position}
        - 技术领域：{techField}
        - 擅长语言：{languages}
        - 实习经历：{internshipInfo}
        - 项目经历：{projectInfo}
        - 个人简介：{selfDesc}

        【面试上下文】
        - 当前问题：{currentQuestion}
        - 候选人回答：{userAnswer}

        【生成要求】
        1. 首先对候选人回答进行直接的点评，指出明显问题。
        2. 随后生成一个带有挑战性的追问,让候选人感到紧张和压力。
        3. 追问要紧密结合岗位、技术领域、项目经历、技能等关键信息，直击要害，避免泛泛而谈。
        4. 只输出点评和追问，用自然段连接，不要有任何额外说明。
        5. 输出问题不需要过长，1个问就行。

        请直接输出点评和追问。连成一段，不要有点评追问的字眼在段落里。注意要结合候选者的回答，注意问题不要太长！！！1个问题就行。`
        },
      project: {
        name: '项目经验面试',
        promptTemplate: `
      你是一名专业的面试官，请根据以下候选人信息和上下文，围绕候选人的项目经历进行深入提问。注意问题不要太长！！！1个问题就行。

      【候选人信息】
      - 目标岗位：{position}
      - 技术领域：{techField}
      - 擅长语言：{languages}
      - 项目经历：{projectInfo}
      - 实习经历：{internshipInfo}
      - 个人简介：{selfDesc}

      【面试上下文】
      - 当前问题：{currentQuestion}
      - 候选人回答：{userAnswer}

      【生成要求】
      1. 先对候选人项目经历的回答进行1句点评，可以肯定成果或指出疑问。
      2. 然后针对项目细节、技术难点、个人贡献等方面进行深入追问，挖掘候选人在项目中的实际作用和解决问题的能力。
      3. 问题应自然引导候选人阐述项目细节、挑战和解决方案。
      4. 语气需专业且具有探索性，避免泛泛而谈。
      5. 只输出项目点评和追问，用自然段连接，不需要任何额外说明。
      6. 注意问题不要太长！！！1个问题就行。

      请直接输出项目点评和追问。连成一段，不要有点评追问的字眼在段落里。注意问题不要太长！！！1个问题就行。`
      },
       case: {
        name: '案例面试',
        promptTemplate: `
      你是一名专业的面试官，请根据以下候选人信息和上下文，围绕候选人的案例回答生成管理或业务场景的追问。注意问题不要太长！！！1个问题就行。

      【候选人信息】
      - 目标岗位：{position}
      - 技术领域：{techField}
      - 擅长语言：{languages}
      - 基础信息：{basicInfo}
      - 项目经历：{projectInfo}
      - 实习经历：{internshipInfo}
      - 个人简介：{selfDesc}

      【面试上下文】
      - 当前问题：{currentQuestion}
      - 候选人回答：{userAnswer}

      【生成要求】
      1. 点评需聚焦问题解决逻辑、资源协调、决策合理性等方面，肯定亮点或指出不足。
      2. 追问需拓展案例场景、增加复杂性或评估候选人的决策与应变能力。
      3. 问题应模拟真实业务或管理场景的复杂性，考察候选人的综合素质和实际操作能力。
      4. 语气需商务化、目标导向，避免泛泛而谈。
      5. 只输出案例点评和追问，用自然段连接，不需要任何额外说明。
      6. 注意问题不要太长！！！1个问题就行。

      请直接输出案例点评和场景追问。连成一段，不要有点评追问的字眼在段落里。注意问题不要太长！！！1个问题就行。`
      },
        behavioral: {
          name: '行为面试',
          promptTemplate: `作为HR面试官，你需要根据候选人的行为回答生成STAR法则追问。请先对回答进行1-2句行为点评（肯定表现或指出信息缺失），然后生成1个自然的行为追问问题。

        【候选人信息】
        - 目标岗位：{position}
        - 技术领域：{techField}
        - 基础信息：{basicInfo}
        - 教育背景：{educationInfo}
        - 实习经历：{internshipInfo}
        - 项目经历：{projectInfo}
        - 校园/社会经历：{socialInfo}
        - 技能特长：{skillsInfo}
        - 证书/奖项：{certInfo}
        - 个人简介：{selfDesc}

        【面试上下文】
        - 当前问题：{currentQuestion}
        - 候选人回答：{userAnswer}

        【行为面试要求】
          1. 点评需关联岗位所需软技能（沟通、团队等）
          2. 追问需补充STAR法则中缺失的要素（如任务细节）
          3. 问题应自然探索候选人的行为动机和结果
          4. 语气需温和但具有引导性
          5. 只输出行为点评和STAR追问，用自然段连接，不需要任何额外说明。
          6. 注意问题不要太长！！！1个问题就行。

          输出格式：先行为点评，再STAR追问，连成一段，不要有点评追问的字眼在段落里。注意问题不要太长！！！1个问题就行。`
        },
        salary: {
          name: '薪资谈判',
          promptTemplate: `作为HR面试官，你需要根据候选人的薪资回答生成谈判追问。请先对回答进行1-2句薪资点评（确认期望或指出矛盾点），然后生成1个自然的薪资谈判问题。

        【候选人信息】
        - 目标岗位：{position}
        - 技术领域：{techField}
        - 擅长语言：{languages}
        - 基础信息：{basicInfo}
        - 教育背景：{educationInfo}
        - 实习经历：{internshipInfo}
        - 项目经历：{projectInfo}
        - 校园/社会经历：{socialInfo}
        - 技能特长：{skillsInfo}
        - 证书/奖项：{certInfo}
        - 个人简介：{selfDesc}

        【面试上下文】
        - 当前问题：{currentQuestion}
        - 候选人回答：{userAnswer}

        【薪资谈判要求】
        1. 点评需围绕薪资期望的合理性、与岗位匹配度，肯定或指出疑点。
        2. 追问需探索候选人薪资期望的依据和灵活性。
        3. 问题应自然引导候选人阐述薪资诉求背后的原因或可协商空间。
        4. 语气需专业且具有协商性，避免直接否定。
        5. 只输出薪资点评和谈判追问，用自然段连接，不需要任何额外说明。

        请直接输出薪资点评和谈判追问，连成一段，不要有点评追问的字眼在段落里。`
        }
      }
    }
  },
  computed:{
     // 获取用户选择的岗位信息
    ...mapGetters('userSelection', {
      getTechField: 'getTechField',
      getPosition: 'getPosition',
      getLanguages: 'getLanguages'
    }),
    // 获取用户简历信息
    ...mapGetters('resumeSDK', {
      resumeResult: 'getResumeResult'
    })
  },
  methods: {
    // 获取所有可用场景
    getAvailableScenarios() {
      return Object.keys(this.scenarioConfig).map(key => ({
        key,
        name: this.scenarioConfig[key].name
      }));
    },
    // 设置当前场景
    setScenario(scenarioKey) {
      if (this.scenarioConfig[scenarioKey]) {
        this.currentScenario = scenarioKey;
        return true;
      }
      return false;
    },
    // 生成问题的主方法
    generateQuestion(currentQuestion, userAnswer, scenario = null) {
      return new Promise((resolve, reject) => {
        if (scenario && this.setScenario(scenario)) {
          console.log(`切换到场景: ${this.scenarioConfig[scenario].name}`);
        }

        if (!currentQuestion || !userAnswer) {
          reject('缺少问题或回答内容');
          return;
        }

        this.isLoading = true;
        this.responseBuffer = '';

        // 重置WebSocket（如果有）
        this.closeModelWS();

        this.getModelWebSocketUrl().then(url => {
          if (!('WebSocket' in window)) {
            reject('浏览器不支持WebSocket,无法生成问题');
            return;
          }

          this.modelWS = new WebSocket(url);
          let questionReceived = false;

          this.modelWS.onopen = () => {
            const prompt = this.buildPrompt(currentQuestion, userAnswer);
            this.sendQuestionPrompt(prompt);
          };

          this.modelWS.onmessage = e => {
            this.handleQuestionResult(e.data, resolve, reject, questionReceived);
          };

          this.modelWS.onerror = e => {
            reject(`WebSocket错误: ${e.message}`);
          };

          this.modelWS.onclose = e => {
            if (!questionReceived) {
              reject(`连接关闭，未收到问题`);
            }
            this.isLoading = false;
          };

          // 设置超时
          setTimeout(() => {
            if (!questionReceived && this.modelWS.readyState !== WebSocket.CLOSED) {
              this.modelWS.close();
              reject('生成问题超时');
            }
          }, 20000); // 20秒超时
        }).catch(error => {
          reject(`获取WebSocket URL失败: ${error.message}`);
        });
      });
    },
    // 构建提示词
  buildPrompt(currentQuestion, userAnswer) {
  const template = this.scenarioConfig[this.currentScenario].promptTemplate;

  // 获取Vuex中的用户数据
  const techField = this.getTechField || '未知技术领域';
  const position = this.getPosition || '未知职位';
  const resumeDatalanguages = this.getLanguages.length > 0
    ? this.getLanguages.join('、')
    : '未提及技术语言';
    //简历信息
  const infoMap=this.extractResumeSections(this.resumeResult);
  const basicInfo = JSON.stringify(infoMap.personal || {});
  const educationInfo = JSON.stringify(infoMap.education || {});
  const internshipInfo = JSON.stringify(infoMap.internship || {});
  const projectInfo = JSON.stringify(infoMap.project || {});
  const socialInfo = JSON.stringify(infoMap.social || {});
  const skillsInfo = JSON.stringify(infoMap.skills || {});
  const certInfo = JSON.stringify(infoMap.cert || {});
  const selfDesc = infoMap.self_desc || '';



  // 构建提示词
  let promptWithUserInfo = template
    .replace('{position}', position)
    .replace('{techField}', techField)
    .replace('{languages}', resumeDatalanguages)
    .replace('{basicInfo}', basicInfo)
    .replace('{educationInfo}', educationInfo)
    .replace('{internshipInfo}', internshipInfo)
    .replace('{projectInfo}', projectInfo)
    .replace('{socialInfo}', socialInfo)
    .replace('{skillsInfo}', skillsInfo)
    .replace('{certInfo}', certInfo)
    .replace('{selfDesc}', selfDesc);

  return promptWithUserInfo;
},
    // 发送提示词到模型
    sendQuestionPrompt(prompt) {
      const params = {
        "header": {
          "app_id": this.appId,
          "uid": "interview-question-generator-" + Date.now()
        },
        "parameter": {
          "chat": {
            "domain": this.modelDomain,
            "temperature": 0.7,
            "max_tokens": 1024
          }
        },
        "payload": {
          "message": {
            "text": [
              { "role": "user", "content": prompt }
            ]
          }
        }
      };

      this.modelWS.send(JSON.stringify(params));
    },
    // 处理模型返回的问题
    handleQuestionResult(resultData, resolve, reject, questionReceived) {
      try {
        const jsonData = JSON.parse(resultData);
        if (jsonData.payload && jsonData.payload.choices && jsonData.payload.choices.text) {
          const content = jsonData.payload.choices.text[0].content.trim();
          // 清理可能的前缀
          const cleanContent = content.replace('生成中...', '').trim();

          if (cleanContent) {
            this.responseBuffer += cleanContent;
          }

          if (jsonData.header.status === 2) {
            // 完整结果
            const formattedQuestion = this.formatQuestionResult(this.responseBuffer);
            resolve(formattedQuestion);
            questionReceived = true;
          }
        }

        if (jsonData.header.code !== 0) {
          reject(`模型错误: ${jsonData.header.code}:${jsonData.header.message}`);
        }
      } catch (error) {
        console.error('解析问题生成结果失败:', error);
      }
    },
    // 格式化问题结果
    formatQuestionResult(content) {
      // 简单清理，可根据需要扩展
      return content.trim().replace(/^[\s\n]+|[\s\n]+$/g, '');
    },
    // 获取模型WebSocket URL
    getModelWebSocketUrl() {
      return new Promise((resolve, reject) => {
        try {
          const modelUrl = new URL(this.modelHttpUrl);
          const host = modelUrl.host;
          const date = new Date().toGMTString();
          const algorithm = 'hmac-sha256';
          const headers = 'host date request-line';
          const signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${modelUrl.pathname} HTTP/1.1`;
          const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.apiSecret);
          const signature = CryptoJS.enc.Base64.stringify(signatureSha);
          const authorizationOrigin = `api_key="${this.apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
          const authorization = btoa(authorizationOrigin);
          const url = `wss://${host}${modelUrl.pathname}?authorization=${authorization}&date=${date}&host=${host}`;
          resolve(url);
        } catch (error) {
          reject(error);
        }
      });
    },
    // 关闭模型WebSocket
    closeModelWS() {
      if (this.modelWS && this.modelWS.readyState !== WebSocket.CLOSED) {
        this.modelWS.close();
      }
      this.modelWS = null;
  },
  extractResumeSections(resumeResult) {
  const sections = [];

  // 个人信息
  sections.push({
    type: 'personal',
    title: '个人信息',
    content: {
      name: resumeResult.name,
      gender: resumeResult.gender,
      birthday: resumeResult.birthday,
      phone: resumeResult.phone,
      email: resumeResult.email,
      city: resumeResult.city,
      degree: resumeResult.degree,
      college: resumeResult.college,
      major: resumeResult.major,
    }
  });
  // 教育背景
  if (Array.isArray(resumeResult.education_objs) && resumeResult.education_objs.length > 0) {
    sections.push({
      type: 'education',
      title: '教育背景',
      content: resumeResult.education_objs
    });
  }

  // 实习经历
  if (Array.isArray(resumeResult.job_exp_objs) && resumeResult.job_exp_objs.length > 0) {
    sections.push({
      type: 'internship',
      title: '实习经历',
      content: resumeResult.job_exp_objs
    });
  }

  // 项目经历
  if (Array.isArray(resumeResult.proj_exp_objs) && resumeResult.proj_exp_objs.length > 0) {
    sections.push({
      type: 'project',
      title: '项目经历',
      content: resumeResult.proj_exp_objs
    });
  }

  // 校园/社会经历
  if (Array.isArray(resumeResult.social_exp_objs) && resumeResult.social_exp_objs.length > 0) {
    sections.push({
      type: 'social',
      title: '校园/社会经历',
      content: resumeResult.social_exp_objs
    });
  }
  // 技能
  if (Array.isArray(resumeResult.skills_objs) && resumeResult.skills_objs.length > 0) {
    sections.push({
      type: 'skills',
      title: '技能特长',
      content: resumeResult.skills_objs
    });
  }

  // 证书
  if (Array.isArray(resumeResult.all_cert_objs) && resumeResult.all_cert_objs.length > 0) {
    sections.push({
      type: 'cert',
      title: '证书/奖项',
      content: resumeResult.all_cert_objs
    });
  }

  // 个人简介
  if (resumeResult.cont_my_desc) {
    sections.push({
      type: 'self_desc',
      title: '个人简介',
      content: resumeResult.cont_my_desc
    });
  }
  console.log(sections)
  const infoMap=this.getResumeInfoMap(sections)
  return infoMap
},
getResumeInfoMap(sections) {
  const infoMap = {};
  sections.forEach(sec => {
    infoMap[sec.type] = sec.content;
  });
  return infoMap;
},
  beforeDestroy() {
    this.closeModelWS();
   },
 },
}
</script>

<style scoped>
</style>
